using AdminApiTemplate.Api.Attributes;
using AdminApiTemplate.Api.Enums;
using AdminApiTemplate.Api.Helpers;
using AdminApiTemplate.Cache;
using AdminApiTemplate.Common.Exceptions;
using AdminApiTemplate.Common.Helpers;
using AdminApiTemplate.Common.Models;
using AdminApiTemplate.Services.AdminUser;
using AdminApiTemplate.Services.Sys;
using AdminApiTemplate.ThirdParty.Redis;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Newtonsoft.Json;
using System.Globalization;

namespace AdminApiTemplate.Api.Controllers.BaseControllers
{
    /// <summary>
    /// 需要有权限才能访问的
    /// </summary>
    public class PermissionRequiredController : Controller
    {
        /// <summary>
        /// 执行前
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            var requestId = RandomHelper.RequestId();
            var rsp = new ApiResponseBase<object>
            {
                ErrorCode = 999,
                ErrorMsg = "系统繁忙，请稍后再试",
                RequestId = requestId
            };

            var sk = context.HttpContext.Request.Headers["Authorization"].FirstOrDefault();
            if (!SKHelper.Check(sk))
            {
                rsp.ReLogin=true;
                rsp.ErrorCode= (int)ErrorCodeEnum.NotAllowed;
                rsp.ErrorMsg="请重新登录";
                var json = JsonConvert.SerializeObject(rsp, CacheHelper.ExcludeNullJsonConfig);
                context.Result = new ContentResult
                {
                    Content = json,
                    ContentType = "application/json",
                    StatusCode = 200,
                };
                return;
            }

            var parts = EncryptHelper.DESDecrypt(sk[0..^1], "1qaz2WSX");
            if (!DateTime.TryParseExact(parts.Substring(0, 14), "yyyyMMddHHmmss", null, DateTimeStyles.None, out var dt))
            {
                rsp.ReLogin=true;
                rsp.ErrorCode= (int)ErrorCodeEnum.NotAllowed;
                rsp.ErrorMsg="请重新登录";
                var json = JsonConvert.SerializeObject(rsp, CacheHelper.ExcludeNullJsonConfig);
                context.Result = new ContentResult
                {
                    Content = json,
                    ContentType = "application/json",
                    StatusCode = 200,
                };
                return;
            }

            var ts = DateTime.Now - dt;
            if (ts.TotalHours>24)
            {
                rsp.ReLogin=true;
                rsp.ErrorCode= (int)ErrorCodeEnum.NotAllowed;
                rsp.ErrorMsg="请重新登录";
                var json = JsonConvert.SerializeObject(rsp, CacheHelper.ExcludeNullJsonConfig);
                context.Result = new ContentResult
                {
                    Content = json,
                    ContentType = "application/json",
                    StatusCode = 200,
                };
                return;
            }

            var id = $"admin:{parts.Substring(20)}";
            var adminUser = RedisHelper.Get<CachedAdminUserDto>(id);
            if (adminUser == null)
            {
                rsp.ReLogin=true;
                rsp.ErrorCode= (int)ErrorCodeEnum.NotAllowed;
                rsp.ErrorMsg="请重新登录";
                var json = JsonConvert.SerializeObject(rsp, CacheHelper.ExcludeNullJsonConfig);
                context.Result = new ContentResult
                {
                    Content = json,
                    ContentType = "application/json",
                    StatusCode = 200,
                };
                return;
            }

            var actionDescriptor = (Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)context.ActionDescriptor;
            var permissionRequiredAttribute = (PermissionRequiredAttribute)actionDescriptor.MethodInfo.GetCustomAttributes(typeof(PermissionRequiredAttribute), true).FirstOrDefault();
            if (permissionRequiredAttribute!=null && !string.IsNullOrEmpty(permissionRequiredAttribute.PermissionCode))
            {
                var permissions = permissionRequiredAttribute.PermissionCode.Split('|').Select(o => o.Trim().ToUpper());
                if (!adminUser.Permissions.Any(w => permissions.Contains(w.ToUpper())))
                {
                    rsp.ReLogin=true;
                    rsp.ErrorCode= (int)ErrorCodeEnum.NotAllowed;
                    rsp.ErrorMsg="You not have no permission to do this.";
                    rsp.ErrorMsg2="没有权限进行此操作";
                    var json = JsonConvert.SerializeObject(rsp, CacheHelper.ExcludeNullJsonConfig);
                    context.Result = new ContentResult
                    {
                        Content = json,
                        ContentType = "application/json",
                        StatusCode = 200,
                    };
                    return;
                }
            }

            AUID = adminUser.AUID;
            ChineseName = adminUser.ChineseName;
            EnglishName = adminUser.EnglishName;
            Permissions = adminUser.Permissions;
            UserType = adminUser.UserType;
            UnderAUIDManages = adminUser.UnderAUIDManages;
            RedisHelper.Set(id, adminUser, TimeSpan.FromHours(4));
            base.OnActionExecuting(context);
        }

        /// <summary>
        /// 当前登录的账号的Id（AdminUser表的Id）
        /// </summary>
        public long AUID { get; set; } = 0;

        /// <summary>
        /// 当前登录的账号的中文名
        /// </summary>
        public string ChineseName { get; set; }

        /// <summary>
        /// 当前登录的账号的英文名
        /// </summary>
        public string EnglishName { get; set; }

        /// <summary>
        /// 当前登录的账号的用户类型，1是BM 2是BD
        /// </summary>
        public int UserType { get; set; }

        /// <summary>
        /// 当前登录的账号的管理的下级
        /// </summary>
        public List<long> UnderAUIDManages { get; set; } = new List<long>();

        /// <summary>
        /// 当前登录的账号的权限
        /// </summary>
        private List<string> Permissions { get; set; } = new List<string>();

        /// <summary>
        /// 是否有权限
        /// </summary>
        /// <param name="permissionCode"></param>
        /// <returns></returns>
        protected bool HasPermission(string permissionCode)
        {
            return Permissions.Contains(permissionCode);
        }

        /// <summary>
        /// 获取分页列表
        /// </summary>
        /// <typeparam name="Tin"></typeparam>
        /// <typeparam name="Tout"></typeparam>
        /// <param name="request"></param>
        /// <param name="tables"></param>
        /// <param name="fields"></param>
        /// <param name="orderByFieldsAll"></param>
        /// <returns></returns>
        public IActionResult GetPagedList<Tin, Tout>(Tin request, string tables, string fields, string orderByFieldsAll, params SqlParameterItem[] sps) where Tin : PagedRequest
        {
            return GetPagedList<Tin, Tout>(request, tables, fields, orderByFieldsAll, null, sps);
        }

        /// <summary>
        /// 获取分页列表
        /// </summary>
        /// <typeparam name="Tin"></typeparam>
        /// <typeparam name="Tout"></typeparam>
        /// <param name="request"></param>
        /// <param name="tables"></param>
        /// <param name="fields"></param>
        /// <param name="orderByFieldsAll"></param>
        /// <returns></returns>
        public IActionResult GetPagedList<Tin, Tout>(Tin request, string tables, string fields, string orderByFieldsAll, Action<List<Tout>> action, params SqlParameterItem[] sps) where Tin : PagedRequest
        {
            if (!request.Export.GetValueOrDefault())
            {
                return new WebHelper(HttpContext, request).Execute(SysUserTypeEnum.AdminUser, AUID.ToString(), () =>
                {
                    var pagedList = DataHelper.GetPagedList<Tin, Tout>(request, tables, fields, orderByFieldsAll, sps);
                    if (action!=null && pagedList.Items!=null && pagedList.Items.Any())
                    {
                        action(pagedList.Items);
                    }
                    return pagedList;
                });
            }
            else
            {
                if (string.IsNullOrEmpty(request.ExportModule))
                {
                    throw new WithCodeException((int)ErrorCodeEnum.CodeError, "导出失败，导出模块必填", "ExportModule必填");
                }

                if (string.IsNullOrEmpty(request.ExportFileName))
                {
                    throw new WithCodeException((int)ErrorCodeEnum.CodeError, "导出失败，导出文件名必填", "ExportFileName必填");
                }

                if (!request.HasExportPermission.GetValueOrDefault())
                {
                    throw new WithCodeException((int)ErrorCodeEnum.NotAllowed, "导出失败，没有权限进行此操作。");
                }

                var host = ConfigHelper.GetSysConfig<string>("ApiHost", null);
                if (string.IsNullOrEmpty(host))
                {
                    throw new WithCodeException((int)ErrorCodeEnum.CodeError, "导出失败，请联系管理员配置ApiHost参数");
                }

                var module = request.ExportModule;
                var folder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Exports", module);
                if (!Directory.Exists(folder))
                {
                    Directory.CreateDirectory(folder);
                }

                var fileName = $"{request.ExportFileName}{RandomHelper.RequestId()}.xlsx";
                var fullName = Path.Combine(folder, fileName);

                Task.Run(() =>
                {
                    var data = DataHelper.GetPagedList<Tin, Tout>(request, tables, fields, orderByFieldsAll, sps);
                    ExcelHelper.Export(fullName, data.Items);
                });

                return new WebHelper(HttpContext, request).Execute(SysUserTypeEnum.AdminUser, AUID.ToString(), () =>
                {
                    return $"{host}/api/Home/Export?module={module}&fileName={fileName}";
                });
            }
        }

        /// <summary>
        /// 新增
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="request"></param>
        /// <param name="tables"></param>
        /// <param name="fields"></param>
        /// <param name="operationType"></param>
        /// <returns></returns>
        public IActionResult Add<T>(T request, string tables, string fields, string operationType)
        {
            return new WebHelper(HttpContext, request).Execute(SysUserTypeEnum.AdminUser, AUID.ToString(), () =>
            {
                var id = default(long);
                var data = DataHelper.Add<T>(request, tables, fields,ref id);
                if (!string.IsNullOrEmpty(operationType))
                {
                    AddOperationLog(new OperationLogRequestModel
                    {
                        AUID = AUID,
                        OperationType = operationType,
                        P1 = JsonConvert.SerializeObject(request),
                        CreateTime=DateTime.Now
                    });
                }
                switch (operationType)
                {
                    case "AddAdminUser":
                        {
                            if (request is AddAdminUserRequestModel pi)
                            {
                                if (pi.RoleIds!=null && pi.RoleIds.Count>0)
                                {
                                    foreach (var roleId in pi.RoleIds)
                                    {
                                        InsertUserRole(new InsertUserRoleRequestModel
                                        {
                                            UserId= id,
                                            CreateTime=DateTime.Now,
                                            RoleId=roleId
                                        });
                                    }
                                }

                                if (pi.BM.HasValue)
                                {
                                    AssignBDToBM(new AssignBDToBMRequestModel
                                    {
                                        UnderAUID = Convert.ToInt32(id),
                                        AUID = pi.BM,
                                        CreateTime=DateTime.Now
                                    });
                                }

                                if (pi.UserType == (int)AdminUserTypeEnum.Sales||pi.UserType==(int)AdminUserTypeEnum.BD)
                                {
                                    AddAssignConfig(id);
                                }
                            }
                            break;
                        }
                }
                
                return data;
            });
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="request"></param>
        /// <param name="tables"></param>
        /// <param name="fields"></param>
        /// <param name="operationType"></param>
        /// <returns></returns>
        public IActionResult Edit<T>(T request, string tables, string fields, string operationType) where T : EditRequest
        {
            return new WebHelper(HttpContext, request).Execute(SysUserTypeEnum.AdminUser, AUID.ToString(), () =>
            {
                var one = DataHelper.GetOne<T>(request, tables, fields);
                var data = DataHelper.Edit<T>(request, tables, fields);
                if (!string.IsNullOrEmpty(operationType))
                {
                    AddOperationLog(new OperationLogRequestModel
                    {
                        AUID = AUID,
                        OperationType = operationType,
                        P1 = JsonConvert.SerializeObject(request, CacheHelper.ExcludeNullJsonConfig),
                        P2 = one == null ? "{}" : JsonConvert.SerializeObject(one, CacheHelper.ExcludeNullJsonConfig),
                        CreateTime = DateTime.Now
                    });
                }
                return data;
            });
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="request"></param>
        /// <param name="tables"></param>
        /// <param name="operationType"></param>
        /// <returns></returns>
        public IActionResult Del<T>(T request, string tables, string operationType) where T : EditRequest
        {
            return new WebHelper(HttpContext, request).Execute(SysUserTypeEnum.AdminUser, AUID.ToString(), () =>
            {
                var data = DataHelper.Del<T>(request, tables);
                if (!string.IsNullOrEmpty(operationType))
                {
                    AddOperationLog(new OperationLogRequestModel
                    {
                        AUID = AUID,
                        OperationType = operationType,
                        P1 = JsonConvert.SerializeObject(request),
                        CreateTime = DateTime.Now
                    });
                }
                return data;
            });
        }

        /// <summary>
        /// 添加操作日志
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private string AddOperationLog(OperationLogRequestModel request)
        {
            if (!request.CreateTime.HasValue)
            {
                request.CreateTime = DateTime.Now;
            }          
            return DataHelper.Add(request, "operationlog", "AUID,OperationType,P1,P2,P3,P4,P5,CreateTime");
        }

        /// <summary>
        /// 添加用户角色
        /// </summary>
        /// <param name="userrole"></param>
        private string InsertUserRole(InsertUserRoleRequestModel userrole)
        {
            return DataHelper.Add(userrole, "UserRole", "UserId,RoleId,CreateTime");             
        }

        /// <summary>
        /// 分配BD给BM
        /// </summary>
        /// <param name="request"></param>
        private string AssignBDToBM(AssignBDToBMRequestModel request)
        {
            var sql = $"update adminuser set ParentId=@AUID where Id=@UnderAUID";
            CacheHelper.DefaultQuery.Execute(sql, new { request.AUID, request.UnderAUID });
            return DataHelper.Add(request, "underauidmanage", "AUID,UnderAUID,CreateTime");
        }

        /// <summary>
        /// 添加分配设置
        /// </summary>
        /// <param name="id"></param>
        private void AddAssignConfig(long id)
        {
            var sql = $"INSERT INTO kolassignconfig (CreateTime, Sales, Assign) SELECT NOW(),t1.Id,(SELECT max(a.Assign)-2 from kolassignconfig a) Num from adminuser t1 WHERE t1.Id=@id and t1.UserType={(int)AdminUserTypeEnum.Sales}";
            CacheHelper.DefaultQuery.Execute(sql, new { id });
        }
    }
}
